home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / source / xdme_1.84_src.lha / XDME / Util / Var / fp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-22  |  15.3 KB  |  559 lines

  1. /* **************************************************
  2.  
  3.         FLEXPRINTF
  4.  
  5. ************************************************** */
  6.  
  7. #include <exec/types.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11.  
  12. #undef    Prototype
  13. #define Prototype extern
  14.  
  15. #define FLEXPRINT_BUFFER 0
  16.  
  17. #ifndef   STREAM
  18. #define   STREAM void*
  19. #endif
  20.  
  21. BOOL         flexprintf (STREAM, BOOL (*)(STREAM, STRPTR), STRPTR, STREAM, STRPTR (*)(STREAM, STRPTR));
  22. BOOL         fpfputs    (FILE*,  char* );
  23.  
  24. //#define ERROR_NO_NAME_OF_QUERY   /* error ("%s:\n%s!\n", mod_name, "No name given"); */
  25. //#define ERROR_NO_VALUE_OF_QUERY  /* error ("%s:\n%s %s!\n", mod_name, "No value for variable", memo); */
  26. //#define ERROR_UNTERMINATED_QUERY /* error ("%s:\n%s!\n", mod_name, "Unterminated variable query"); */
  27. //#define ERROR_NO_MEMORY
  28. //#define ERROR_NO_FILE        error ("%s:\n%s %s!\n", mod_name, "File not found\n", name);
  29. #define ERROR_NO_NAME_OF_QUERY     puts("NO_QUERY_NAME");
  30. #define ERROR_NO_VALUE_OF_QUERY  printf("NO_QUERY_RESULT <<%s>>\n", memo + 2);
  31. #define ERROR_UNTERMINATED_QUERY printf("UNTERMINATED_QUERY <<%s>>\n", memo);
  32. #define ERROR_WRITE_FAILED     puts("WRITE_FAILED");
  33. #define ERROR_NO_MEMORY      puts("NO_MEMORY");
  34.  
  35. #define INC(x) ++(x)
  36. #define DEC(x) --(x)
  37.  
  38.  
  39. /* MACROS 18-08-93 by b_noll */
  40. #define is_char(x)     (isalnum(x) || ((x) ==  '_') || ((x) == '.'))
  41. #define is_command(x)  (is_varstart(*(x)) && (*(x) == (x)[1]))
  42. #define is_comment(x)  (*(x) == '#')
  43.  
  44.  
  45. /* ---- definitions for "is_varstart" */
  46. #ifdef SLOW_VARSTART
  47. # define is_varstart(x) strchr(query_starts, x)
  48. #else
  49. # define is_varstart(x) (((x) == '$') || ((x) == '%'))
  50.             /*    ((x) == '%') */                  /* <<< use that line to enable only   '%'-variables */
  51.             /*    ((x) == '$') */                  /* <<< use that line to enable only   '$'-variables */
  52.             /* (((x) == '$') || ((x) == '%')) */ /* <<< use that line to enable '$' or '%'-variables */
  53. #endif
  54.  
  55.  
  56. /* ---- definitions for query-recognition */
  57. #define QUERY_START    "%$" /* <<< this line only has affect if SLOW_VARSTART is defined */
  58.  
  59. /* ---- definitions for bracket-recognition */
  60. #ifdef AMIGA
  61. # define BRACKET_OPEN  "(`[{<\253" /* the last one is '<<' */
  62. # define BRACKET_CLOSE ")']}>\273" /* the last one is '>>' */
  63. #else
  64. # define BRACKET_OPEN  "(`[{<"
  65. # define BRACKET_CLOSE ")']}>"
  66. #endif /* AMIGA */
  67.  
  68.  
  69.  
  70. #ifdef XDME
  71.  
  72. /* ---- XDME uses a subset of the possibles methods; */
  73. /*    we currently do only allow $(...) and $`...' */
  74. /*    to be recognized and replaced */
  75. # undef SLOW_VARSTART
  76. # undef is_varstart
  77. # undef QUERY_START
  78. # undef BRACKET_OPEN
  79. # undef BRACKET_CLOSE
  80.  
  81.  
  82. # define is_varstart(x) ((x) == '$')
  83. # define QUERY_START    "$"
  84. # define BRACKET_OPEN    "(`"
  85. # define BRACKET_CLOSE    ")'"
  86.  
  87. #endif /* XDME */
  88.  
  89.  
  90. /* ---- there are currently 2 Versions of flexprintf here;
  91. **    the first - older - version was used over 'bout 1/2 a year
  92. **    and did not show any error; the second one is not yet really
  93. **    tested w/ "XDME", it was used with "Nyktos Ophthalmoi" for
  94. **    'bout 2 months.
  95. **    please do't ask me, why I created 2nd version, there was
  96. **    a reason, but I can't remember ... */
  97.  
  98. #ifdef OLD
  99.  
  100.  
  101. /*****************************************************************************
  102.  
  103.     NAME
  104.     flexprintf
  105.  
  106.     PARAMETER
  107.     STREAM outstream;
  108.     ;BOOL (*writechar)  (STREAM, char);
  109.     BOOL  (*writestring)(STREAM, STRPTR);
  110.     STRPTR format;
  111.     STREAM instream;
  112.     STRPTR (*getstring)(STREAM, STRPTR);
  113.  
  114.     RESULT
  115.     success
  116.  
  117.     RETURN
  118.     BOOL;
  119.  
  120.     DESCRIPTION
  121.     similar to C_sprintf but slightly different.
  122.  
  123.     wir parsen ein template, das
  124.     $(...) oder %(...) oder ${...} oder %{...} oder
  125.     $«...» oder %«...» oder $<...> oder %<...> oder
  126.     $[...] oder %[...] oder $`...' oder %`...'
  127.     als signalworte hat;
  128.     was zwischen den Klammern steht, wird an
  129.     getstring uebergeben; dessen Ergebnis
  130.     (wir erwarten IMMER strings) wird dann
  131.     eingesetzt.
  132.  
  133.     man kann die Funktion auf 2 sehr unterschiediche
  134.     Weisen verwenden:
  135.         wie sprintf - in diesem Falle ignoriert die
  136.     getfunktion das 2. Argument sondern gibt jedesmal den
  137.     "naechsten" wert zurueck
  138.         wie hier gedacht - in diesem falle liest die getfunktion
  139.     aus einem baum o.ae. den Wert, der der namen von arg2 traegt.
  140.  
  141.     NOTES
  142.     STREAM == APTR
  143.     format must not be const!
  144.  
  145.     not like in normal XDME-scripts there MUST be a form
  146.     of quotes around any variable!
  147.     for XDME "%" and "<...>" "«...»" "[...]" "{...}" were
  148.     disabled.
  149.  
  150.     BUGS
  151.     we do ignore the result of our writestring
  152.     and we do always return TRUE
  153.     (to fix - change "writestring..."
  154.           into     "if (!writestring...) return (FALSE);")
  155.  
  156.     EXAMPLES
  157.  
  158.     SEE ALSO
  159.  
  160.     INTERNALS
  161.  
  162.     HISTORY
  163.     21-07-93    b_noll  created
  164.     18-08-93    b_noll modified for XDME
  165.     27-09-94    b_noll brackets may be nested now
  166.  
  167. ******************************************************************************/
  168.  
  169. BOOL flexprintf (STREAM outstream, BOOL (*writestring)(STREAM, STRPTR), STRPTR format, STREAM instream, STRPTR (*getstring)(STREAM, STRPTR))
  170. {
  171.     char    * cptr = format;
  172.     unsigned char curr;
  173.     unsigned char attn = 0;
  174.  
  175.     for (; (curr = *format) != 0; ++format) {
  176.     if (is_varstart(curr)) {
  177.         if (attn) *cptr = attn;
  178.         *format = 0;
  179.         writestring (outstream, cptr);
  180.         cptr = format;
  181.         attn = curr;
  182.         continue;
  183.     } /* if */
  184.  
  185.     if (attn) {
  186.         char scan = 0;
  187.  
  188.         switch (curr) {
  189.      /* some inconsistancies to XDME were commented out */
  190.      /* case '[': scan = ']'; break; */
  191.      /* case '«': scan = '»'; break; */
  192.      /* case '<': scan = '>'; break; */
  193.      /* case '{': scan = '}'; break; */
  194.         case '(': scan = ')'; break;
  195.         case '`': scan = '\''; break;
  196.         } /* switch */
  197.  
  198.         if (scan) {
  199.         char * memo;
  200.         char * rslt;
  201.  
  202.         ++format;
  203.         memo = format;
  204. #if 1 /* nested brackets */
  205.         {
  206.             unsigned char start = curr;
  207.             int stack = 0;
  208.             while ((curr = *format) && (stack || (curr != scan))) {
  209.             if (curr == start)
  210.                 ++stack;
  211.             if (curr == scan)
  212.                 --stack;
  213.             ++format;
  214.             } /* while */
  215.         }
  216. #else
  217.         while ((curr = *format) && (curr != scan)) {
  218.             ++format;
  219.         } /* while */
  220. #endif
  221.  
  222.         *format = 0;
  223.         if (*memo) {
  224.             rslt = getstring (instream, memo);
  225.             if (rslt) {
  226.             writestring (outstream, rslt);
  227.  
  228.             *format = scan;
  229.             attn    = 0;
  230.             cptr    = format+1;
  231.             continue;
  232.  
  233.             } else {
  234.             ERROR_NO_VALUE
  235.             } /* if */
  236.         } else {
  237.             ERROR_NO_NAME
  238.         } /* if */
  239.         *format = scan;
  240.         } /* if */
  241.  
  242.         *cptr = attn;
  243.         attn  = 0;
  244.     } /* if */
  245.     } /* for */
  246.     writestring (outstream, cptr);
  247.     return (TRUE);
  248.  
  249. } /* flexprintf */
  250.  
  251. #else /* !OLD */
  252.  
  253.  
  254. /*****************************************************************************
  255.  
  256.     NAME
  257.     flexprintf
  258.  
  259.     PARAMETER
  260.     STREAM outstream;
  261.     BOOL (*writestring)(STREAM, STRPTR);
  262.         ; we expect writestring to return <>0 on Success and
  263.         ; 0 in case of any Failure.
  264.     STRPTR tmplt;
  265.         ; Format is destroyed during the scan, we cannot
  266.         ; use const-strings in System with mem-protection
  267.     STREAM instream;
  268.     STRPTR (*getstring)(STREAM, STRPTR);
  269.  
  270.     RESULT
  271.     success
  272.  
  273.     RETURN
  274.     BOOL;
  275.  
  276.     DESCRIPTION
  277.     similar to C/sprintf but slightly different in usage and syntax:
  278.         while sending tmplt through "writestring(outstream,...)",
  279.     we do replace occurancies of [$%][[(`{|<]char-seq[])'}>] with
  280.     the string, that is returned by "getstring(instream, char-seq)";
  281.     the meaning of [$%] can be escaped by duplicating the character.
  282.  
  283.  
  284.     NOTES
  285.     * tmplt MUST NOT be const! (see BUGS)
  286.       for _flexprintf in any case and for flexprintf
  287.       as long as FLEXPRINT_BUFFER is not defined to 1
  288.  
  289.     * not like in normal Shell- or XDME-scripts there MUST be a form
  290.       of quotes around any variable!
  291.  
  292.     * formatting of replaced variables must be supported by the
  293.       get-function, if such features are needed.
  294.  
  295.     * between the brackets of a variable-query there must be at least
  296.       one char; empty variablenames are not allowed (also if Your getstring
  297.       knows, what is wanted), and lead to a break.
  298.  
  299.     * getstring returning NULL means an error has occured; we will break
  300.       for this reason. Empty strings should be given via "".
  301.       Furthermore we do not free the strings gotten from getstring(),
  302.       since we don't know, if they are static or not, so if these strings
  303.       are dynamically created, You should store them in a static variable.
  304.       my preferred way looks like the following:
  305.         char *getvar(void *x, char *n) {
  306.         static char *ptr = NULL;
  307.         if (ptr) free(ptr);
  308.         ptr = ...;
  309.         return ptr;
  310.         }
  311.  
  312.  
  313.     * not terminating a query will cause a break, if there is no other
  314.       query behind, else the result is not defined.
  315.  
  316.     * we use different macros to inticate the common errors, which are
  317.       recognized: ERROR_NO_NAME_OF_QUERY, ERROR_NO_VALUE_OF_QUERY and
  318.       ERROR_UNTERMINATED_QUERY, ERROR_NO_MEMORY; they are defined to do nothing, so You
  319.       might want to redefine them to Your needs.
  320.  
  321.     Please note, that "%$" and "(`[{<«"/")']}>»" may be changed via some
  322.     defines described below:
  323.  
  324.     * the macro "is_varstart" is used to recognize %/$ - You might want to
  325.       redefine it according to Your needs (see above for different examples)
  326.       if defined "SLOW_VARSTART" You can use the define "QUERY_START" to
  327.       define a list of characters, which may be used as start of a query-
  328.       indicator.
  329.  
  330.     * the defines "BRACKET_OPEN" and "BRACKET_CLOSE" can be used to define
  331.       the different open-brackets and their corresponding close-brackets
  332.       (see above for examples)
  333.  
  334.     * to gain more flexibility You may directly call _flexprintf()
  335.       which has the additional parameters query_starts ("$%"),
  336.       open_brackets ("([{...") and close_brackets (")]}...")
  337.  
  338.     BUGS
  339.     * tmplt is temporarily destroyed during the scan. this is done,
  340.       since we have no information about a necessary buffersize to
  341.       keep a string in, but we wanted to use string-operations instead
  342.       of character operations for writestring.
  343.       (the described behaiviour can be changed (at least for flexprintf,
  344.       not for _flexprintf) by defining FLEXPRINT_BUFFER to 1. (that toggle
  345.       makes flexprintf create a copy of the template and send the copy
  346.       to _flexprintf))
  347.  
  348.     EXAMPLES
  349.  
  350.     SEE ALSO
  351.  
  352.     INTERNALS
  353.     * Funktionsweise:
  354.       wir parsen ein template, das normalerweise
  355.       $(...) oder %(...) oder ${...} oder %{...} oder
  356.       $«...» oder %«...» oder $<...> oder %<...> oder
  357.       $[...] oder %[...] oder $`...' oder %`...'
  358.       als signalworte hat; sobald wir auf ein %/$ stossen, wird der
  359.       bisher geparste und nicht ausgegebene Teil des templates nach
  360.       writestring geschickt. Falls nach %/$ dann eine der Klammern kommt,
  361.       wird, was zwischen den Klammern steht, an getstring uebergeben,
  362.       dessen Ergebnis (wir erwarten IMMER strings) wird dann an
  363.       writestring geschickt. Um die Bedeutung von %/$ zu loeschen
  364.       muss das entsprechende Symbol dupliziert werden, nur eines der
  365.       beiden wird dann ausgegeben. Falls keine bracket folgt, ist eine
  366.       Verdopplung eigentlich unnoetig, sollte aber dennoch erfolgen.
  367.  
  368.     * Anwendung:
  369.       man kann die Funktion auf 2 sehr unterschiediche
  370.       Weisen verwenden:
  371.         wie sprintf - in diesem Falle ignoriert die
  372.       get-funktion das 2. Argument und gibt jedesmal den
  373.       "naechsten" wert zurueck
  374.         wie hier gedacht - in diesem falle liest die getfunktion
  375.       aus einem baum o.ae. den Wert, der der namen von arg2 traegt.
  376.  
  377.  
  378.     HISTORY
  379.     21-07-93    b_noll created
  380.     17-08-93    b_noll rewritten without "writechar()"
  381.     18-08-93    b_noll modified for XDME
  382.     01-05-94    b_null major rewrites ...
  383.  
  384. ******************************************************************************/
  385.  
  386.  
  387. BOOL _flexprintf (STREAM outstream, BOOL (*writestring)(STREAM, STRPTR), STRPTR tmplt, STREAM instream, STRPTR (*getstring)(STREAM, STRPTR), const STRPTR query_starts, const STRPTR open_brackets, const STRPTR close_brackets) {
  388.     unsigned char *memo = tmplt;
  389.     unsigned char  curr;
  390.     unsigned char  attn = 0;
  391.  
  392.     for (; (curr = *tmplt) != 0; ++tmplt) {
  393.  
  394.     /* ---- seems, that we are starting a query, output all chars up to here, mark the pos w/ memo */
  395. #ifdef SLOW_VARSTART
  396.     if (strchr(query_starts, curr))
  397. #else
  398.     if (is_varstart(curr))
  399. #endif
  400.     {
  401.  
  402.         /* ---- previous char was the same? - then allow output of one of'em */
  403.         /*        that hack was done to allow something like escaping; now we  */
  404.         /*        forbid a query by preceding it with two the same varstarts     */
  405.         if (curr == attn) {
  406.         memo = tmplt;
  407.         attn = 0;
  408.         continue;
  409.         } /* if */
  410.  
  411.         /* ---- output the tmplt up to this point and     */
  412.         /*        mark the position with an additional ptr  */
  413.         /*        keep also a copy of varstart to recognize */
  414.         /*        duplicates in order to ignore them          */
  415.  
  416.         /* ---- we do temporarily modify tmplt here!!!! */
  417.         *tmplt = 0;
  418.         if (!writestring (outstream, memo)) {
  419.         *tmplt = curr;
  420.         ERROR_WRITE_FAILED
  421.         return FALSE;
  422.         } /* if */
  423.         *tmplt = curr;
  424.  
  425.         memo   = tmplt;
  426.         attn   = curr;
  427.         continue;
  428.     } /* if varstart */
  429.  
  430.     if (attn) {
  431.         unsigned char scan = 0;
  432.  
  433.         attn    = 0;
  434.  
  435.         /* ---- check, if the current character is an open-bracket    */
  436.         /*        and get the close-bracket, that is correponding to    */
  437.         /*        this open-bracket                    */
  438.         {
  439.         int i;
  440.         for (i = 0; open_brackets[i]; ++i) {
  441.             if (curr == open_brackets[i]) {
  442.             scan = close_brackets[i];
  443.             break;
  444.             } /* if */
  445.         } /* for */
  446.         }
  447.  
  448.         /* ---- we found a bracket after var_start */
  449.         if (scan) {
  450.         char * rslt;
  451.  
  452.         /* ---- skip the open-bracket */
  453.         ++tmplt;
  454.  
  455.         /* ---- search the close-bracket */
  456. #if 1
  457.         {
  458.             unsigned char start = curr;
  459.             int stack = 0;
  460.             while ((curr = *tmplt) && (stack || (curr != scan))) {
  461.             if (curr == start)
  462.                 ++stack;
  463.             if (curr == scan)
  464.                 --stack;
  465.             ++tmplt;
  466.             } /* while */
  467.         }
  468. #else
  469.         while ((curr = *tmplt) && !(curr == scan))
  470.             ++tmplt;
  471. #endif
  472.  
  473.         /* ---- make sure we have found a terminating close-bracket */
  474.         if (!curr) {
  475.             ERROR_UNTERMINATED_QUERY
  476.             return FALSE;
  477.         } /* if */
  478.  
  479.         /* ---- make sure we have got at least one char */
  480.         /*    between the backets            */
  481.         if (tmplt == memo + 2) {
  482.             ERROR_NO_NAME_OF_QUERY
  483.             return FALSE;
  484.         } /* if */
  485.  
  486.         /* ---- query for the variable described between */
  487.         /*    the brackets                 */
  488.  
  489.         /* ---- here we do temporarily modify tmplt!!! */
  490.         *tmplt = 0;
  491.         rslt = getstring (instream, memo + 2);
  492.         *tmplt = scan;
  493.  
  494.         /* ---- make sure we got a valid string from getstring() */
  495.         if (!rslt) {
  496.             ERROR_NO_VALUE_OF_QUERY
  497.             return FALSE;
  498.         } /* if !rslt */
  499.  
  500.         /* ---- output the resultstring */
  501.         if (!writestring (outstream, rslt)) {
  502.             ERROR_WRITE_FAILED
  503.             return FALSE;
  504.         } /* if */
  505.  
  506.         memo = tmplt+1;
  507.         } /* if bracket */
  508.     } /* if attn */
  509.     } /* for */
  510.  
  511.     if (!writestring (outstream, memo)) {
  512.     ERROR_WRITE_FAILED
  513.     return FALSE;
  514.     } /* if */
  515.  
  516.     return TRUE;
  517. } /* _flexprintf */
  518.  
  519.  
  520. Prototype BOOL flexprintf (STREAM outstream, BOOL (*writestring)(STREAM, STRPTR), STRPTR tmplt, STREAM instream, STRPTR (*getstring)(STREAM, STRPTR));
  521. BOOL flexprintf (STREAM outstream, BOOL (*writestring)(STREAM, STRPTR), STRPTR tmplt, STREAM instream, STRPTR (*getstring)(STREAM, STRPTR)) {
  522. #if defined(FLEXPRINT_BUFFER) && FLEXPRINT_BUFFER
  523.     char *dup;
  524.     BOOL  rslt;
  525.  
  526.     if (NULL == (dup = strdup(tmplt))) {
  527.     ERROR_NO_MEMORY
  528.     return FALSE;
  529.     } /* if */
  530.  
  531.     if (!writestring)
  532.     writestring = fpfputs;
  533.  
  534.     rslt = _flexprintf(outstream, writestring, dup, instream, getstring, QUERY_START, BRACKET_OPEN, BRACKET_CLOSE);
  535.     free (dup);
  536.     return rslt;
  537. #else
  538.     return _flexprintf(outstream, writestring, tmplt, instream, getstring, QUERY_START, BRACKET_OPEN, BRACKET_CLOSE);
  539. #endif
  540. } /* flexprintf */
  541.  
  542.  
  543. #endif /* OLD */
  544.  
  545.  
  546. Prototype BOOL fpfputs (FILE *out, char* str);
  547. BOOL fpfputs (FILE *out, char* str) {
  548.     if (!*str) return 1;
  549.     if (!out)  out = stdout;
  550.     return (BOOL)!fputs(str, out);
  551. } /* fpfputs */
  552.  
  553.  
  554.  
  555.  
  556.  
  557.  
  558.  
  559.